﻿#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <thread>
#include <stack>
#include <ctime>
#include <FinderData.hpp>
#include "public.h"
#define test_file  R"(C:\Users\17616\Desktop\本科毕设\实验数据记录\2021-1-2数据\part3\合成.tiff)"
#define test_file2  R"(C:\Users\17616\Desktop\本科毕设\实验数据记录\2021-1-2数据\part3\[2021年1月2日164039][VP101M F4 2^21us][内反射暗场 2A电流][玻璃片0].png)"

std::string ui_title = "ui";//窗口标题
cv::Mat ui;//显示窗口数据
cv::Mat tiff;//图片数据
std::string tiff_path;
cv::Mat tiffu8;//设置曝光时间之后的u8版本的数据
cv::Rect ROI;//当前显示区域的roi
std::stack<cv::Rect> ROI_stack;


#define ENTER 13
#define UP 2490368
#define DOWN 2621440
#define LEFT 2424832
#define RIGHT 2555904
#define ESC 27

float ui_scale = 1;
float expTime = 128 * 1024;//us
//size_t Expend = 1.0;//放大倍率

void get_hist_info();
void show_sum_area();
template<bool log_flag = true>
void show_threshold_area() {
    std::string path = GetFilePath(tiff_path);
    path = GetFilePath(path.substr(0, path.size() - 1));
    path += "FinderWorkSpace.xlsx";
    std::cout << path << std::endl;
    FinderData finderData;
    finderData.open(path);
    for (int i = 0; i < finderData.size(); ++i) {
        if (finderData("当量", i).value().get<int>() != 0) {
            auto x = finderData("x", i).value().get<int>();
            auto y = finderData("y", i).value().get<int>();
            auto w = finderData("w", i).value().get<int>();
            auto h = finderData("h", i).value().get<int>();
            x += w / 2;
            y += h / 2;
            w = 30;
            h = 30;
            x -= w / 2;
            y -= h / 2;
            cv::Rect ROI_d;
            ROI_d.x = MAX(x - w * 2, 0);
            ROI_d.y = MAX(y - h * 2, 0);
            ROI_d.width = MIN(w * 5, tiff.size().width - ROI_d.x);
            ROI_d.height = MIN(h * 5, tiff.size().height - ROI_d.y);
            MyOtsu<log_flag>(tiff(ROI_d), ui(ROI_d), true);
        }
    }
}
void MouseCallback(int event, int x, int y, int flags, void *userdata);
int main(int argn, const char **argv) {
    if (argn == 1) {
        return 0;
    } else if (strcmp(argv[1], "--test") == 0) {
        tiff_path = test_file;
        tiff = cv::imread(tiff_path, cv::IMREAD_UNCHANGED);
    } else {
        std::cout << "file= " << argv[1] << std::endl;
        tiff = cv::imread(argv[1], cv::IMREAD_UNCHANGED);
        ui_title = GetFileName(GetFilePathWithoutType(argv[1]));
        tiff_path = argv[1];
    }
    ROI.x = 0;
    ROI.y = 0;
    ROI.height = tiff.size().height;
    ROI.width = tiff.size().width;
    ui_scale = MAX((float) tiff.size().height / 1400, (float) tiff.size().width / 2880);
    cv::namedWindow("ui", cv::WINDOW_NORMAL);
    cv::setWindowTitle("ui", ui_title);
    cv::setMouseCallback("ui", MouseCallback, &tiff);
    Calculate_u8(tiff, ui, expTime);
    cv::imshow("ui", ui);
    cv::resizeWindow("ui", (float) tiff.size().width / ui_scale, (float) tiff.size().height / ui_scale);
//    cv::resizeWindow("ui", 800,600);

    int key;
    std::string str;
    cv::Rect testROI;
    while (1) {
        key = cv::waitKeyEx();
        switch (key) {
            case LEFT:
                expTime *= 0.5;
                break;
            case RIGHT:
                expTime *= 2;
                break;
            case UP:
                ui_scale *= 0.9;
                cv::resizeWindow("ui", (float) tiff.size().width / ui_scale, (float) tiff.size().height / ui_scale);
                break;
            case DOWN:
                ui_scale *= 1.1;
                cv::resizeWindow("ui", (float) tiff.size().width / ui_scale, (float) tiff.size().height / ui_scale);
                break;
            case -1:
                return 0;
            case 't':
                std::cout << "输入单位加曝光时间如(us 1234)" << std::endl;
                std::cout << '>';
                std::cin >> str >> expTime;
                if (str == "ms") { expTime *= 1000; }
                break;
            case 's':
                std::cout << "显示积分区域" << std::endl;
                show_sum_area();
                cv::imshow("ui", ui(ROI));
                continue;
                break;
            case 'd':
                std::cout << "计算阈值分割" << std::endl;
                show_threshold_area();
                cv::imshow("ui", ui(ROI));
                continue;
                break;
            case 'f':
                std::cout << "计算阈值分割，无log版本" << std::endl;
                show_threshold_area<false>();
                cv::imshow("ui", ui(ROI));
                continue;
                break;
            case 'h':
                std::cout << "统计当前ROI下的直方图信息...";
                get_hist_info();
                std::cout << "完成" << std::endl;
                continue;
                break;
            default:
                printf("key = %d\r\n", key);
                continue;
                break;
        }
        Calculate_u8(tiff, ui, expTime);
        cv::imshow("ui", ui(ROI));
    }
    return 0;
}


void MouseCallback(int event, int x, int y, int flags, void *userdata) {
    int big_x = x + ROI.x;
    int big_y = y + ROI.y;
    //以上是计算在大图当中的坐标
    int WheelDelta;

    static int drag_x;//计算用于拖动的起点
    static int drag_y;
    static bool drag_flag = false;//拖动状态
    static clock_t drag_last_time;
#define CLOCKS_PER_FRAME (CLOCKS_PER_SEC/60)
    switch (event) {
        case cv::EVENT_LBUTTONDOWN:
            printf("x=%d,y=%d,v1=%d,v2=%f,exp=%.1fus\r\n", big_x, big_y,
                   ui.at<uchar>(big_y, big_x),
                   tiff.at<float>(big_y, big_x),
                   expTime);
            break;
        case cv::EVENT_MOUSEWHEEL:
            WheelDelta = cv::getMouseWheelDelta(flags);
            if (WheelDelta >= 0) {
                int width = ROI.width;
                int height = ROI.height;
                if (width > 10 && height > 10) {
                    //放大图片
                    ROI_stack.push(ROI);//保存当前ROI
                    //计算ROI区域
                    int x1 = x - (x) / 2;
                    int x2 = x + (width - x) / 2;
                    int y1 = y - (y) / 2;
                    int y2 = y + (height - y) / 2;
                    ROI = cv::Rect(ROI.x + x1, ROI.y + y1, MAX(x2 - x1, 0), MAX(y2 - y1, 0));
                    cv::imshow("ui", ui(ROI));
                }
                std::cout << "Wheel=" << WheelDelta << ' ' << ROI << std::endl;
            } else {
                if (!ROI_stack.empty()) {
                    //缩小
                    ROI = ROI_stack.top();
                    ROI_stack.pop();
                    std::cout << "Wheel=" << WheelDelta << ' ' << ROI << std::endl;
                    cv::imshow("ui", ui(ROI));
                }
            }
            break;
        case cv::EVENT_MBUTTONDOWN:
            drag_flag = true;
            drag_x = ROI.x + x;
            drag_y = ROI.y + y;
            drag_last_time = clock();
            break;
        case cv::EVENT_MBUTTONUP:
            drag_flag = false;
            //退出拖动时再重绘制一下
            ROI.x = -x + drag_x;
            ROI.y = -y + drag_y;
            //限制ROI到合法区域
            ROI.x = MAX(0, ROI.x);
            ROI.x = MIN(tiff.size().width - ROI.width, ROI.x);
            ROI.y = MAX(0, ROI.y);
            ROI.y = MIN(tiff.size().height - ROI.height, ROI.y);
            cv::imshow("ui", ui(ROI));
            break;
        case cv::EVENT_MOUSEMOVE:
            if (drag_flag && clock() - drag_last_time > CLOCKS_PER_FRAME) {
                drag_last_time = clock();
                ROI.x = -x + drag_x;
                ROI.y = -y + drag_y;
                //限制ROI到合法区域
                ROI.x = MAX(0, ROI.x);
                ROI.x = MIN(tiff.size().width - ROI.width, ROI.x);
                ROI.y = MAX(0, ROI.y);
                ROI.y = MIN(tiff.size().height - ROI.height, ROI.y);
                cv::imshow("ui", ui(ROI));
            }
            break;
        default:
            break;
    }
}


void show_sum_area() {
    std::string path = GetFilePath(tiff_path);
    path = GetFilePath(path.substr(0, path.size() - 1));
    path += "FinderWorkSpace.xlsx";
    std::cout << path << std::endl;
    FinderData finderData;
    finderData.open(path);
    for (int i = 0; i < finderData.size(); ++i) {
        if (finderData("当量", i).value().get<int>() != 0) {
            auto x = finderData("x", i).value().get<int>();
            auto y = finderData("y", i).value().get<int>();
            auto w = finderData("w", i).value().get<int>();
            auto h = finderData("h", i).value().get<int>();
            for (int c = x; c < x + w; ++c) {
                ui.at<uchar>(y + h - 1, c) ^= 255;
                ui.at<uchar>(y, c) ^= 255;
            }
            for (int r = y; r < y + h; ++r) {
                ui.at<uchar>(r, x + w - 1) ^= 255;
                ui.at<uchar>(r, x) ^= 255;
            }
        }
    }
}

void get_hist_info() {
    XLDocument doc;
    XLWorksheet wks;
    std::string path = GetFilePath(tiff_path) + "hist_info.csv";
    if (std::filesystem::exists(path)) {
        std::filesystem::remove(path);
    }
    std::ofstream outFile;
    outFile.open(path);
    auto ROI_copy = ROI;
    ROI_copy.x += ROI_copy.width/2;
    ROI_copy.y += ROI_copy.height/2;
    ROI_copy.width = 150;
    ROI_copy.height = 150;
    ROI_copy.x -= ROI_copy.width/2;
    ROI_copy.y -= ROI_copy.height/2;
    outFile<<"no log"<<','<<"log"<<std::endl;
    for (int r = ROI_copy.y; r < ROI_copy.y + ROI_copy.height; ++r) {
        for (int c = ROI_copy.x; c < ROI_copy.x + ROI_copy.width; ++c) {
            auto buff = tiff.at<float>(r, c);
            outFile<<buff<<','<<log(buff)<<std::endl;
        }
    }
    outFile.close();
}
